package main

import (
	"context"
	"flag"
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/rpc"
	"go.uber.org/zap"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"math/big"
	"shendaNFT/config"
	"shendaNFT/pkg/contract/shendaNFT"
	"shendaNFT/pkg/log"
	"shendaNFT/pkg/model"
	"strconv"
)

func main() {
	// 读取参数
	logLevel := zap.LevelFlag("logLevel", zap.DebugLevel, "log level")
	configFile := flag.String("config", "config.json", "config file path")
	flag.Parse()
	// 配置文件和日志
	ctx := context.Background()
	cfg := config.New(*configFile)
	logger := log.New(logLevel)
	// 连接区块链
	rpcClient, err := rpc.Dial(cfg.Ethereum.WS)
	if err != nil {
		logger.Sugar().Panicw("try connect blockchain failure", "error", err.Error())
	}
	clt := ethclient.NewClient(rpcClient)
	chainID, err := clt.ChainID(ctx)
	if err != nil {
		logger.Sugar().Panicw("try connect blockchain failure", "error", err.Error())
	}
	logger.Sugar().Debugw("connected blockchain", "ws", cfg.Ethereum.WS, "chainID", chainID.String())
	// 连接数据库
	db, err := gorm.Open(mysql.Open(cfg.DB.DSN), &gorm.Config{})
	if err != nil {
		logger.Sugar().Panicw("try connect db failure", "error", err.Error())
	}

	// 加载需要进行补全的数据
	var chainExchanges []model.ChainExchange
	db.Where("tx_hash = ? and block_number = ?", "", "").Find(&chainExchanges)

	if len(chainExchanges) == 0 {
		logger.Sugar().Debugw("no data")
		return
	}
	// 提取合约地址和相关的tokenID
	addrs := make(map[string][]*big.Int)
	for i := 0; i < len(chainExchanges); i++ {
		addrs[chainExchanges[i].ContractAddress] = append(addrs[chainExchanges[i].ContractAddress], big.NewInt(int64(chainExchanges[i].TokenID)))
	}
	//
	for addr, tokenIDs := range addrs {
		fmt.Printf("测试 合约地址 %s \n", addr)
		nftContract, err := shendaNFT.NewShenDaNFT(common.HexToAddress(addr), clt)
		if err != nil {
			logger.Sugar().Panicw("try connect db failure", "error", err.Error())
		}
		transfer, err := nftContract.FilterTransfer(&bind.FilterOpts{}, nil, nil, tokenIDs)
		if err != nil {
			logger.Sugar().Panicw("try connect db failure", "error", err.Error())
		}
		for transfer.Next() {
			// 条件更新
			var ce model.ChainExchange
			rst := db.Where("contract_address = ?", addr).
				Where("buy_wallet_address = ?", transfer.Event.To.String()).
				Where("seller_wallet_address = ?", transfer.Event.From.String()).
				Where("token_id = ?", transfer.Event.TokenId.String()).
				First(&ce)
			if rst.RowsAffected > 0 {
				rst := db.Model(&ce).
					Updates(model.ChainExchange{TxHash: transfer.Event.Raw.TxHash.String(), BlockNumber: strconv.FormatUint(transfer.Event.Raw.BlockNumber, 10)})
				if rst.Error != nil {
					logger.Sugar().Panicw("try updates db failure", "error", err.Error())
				}
			}
		}
	}
}

//func art() {
//	var arts []model.Art
//	db.Where("block_number = ?", "").Find(&arts)
//
//	//
//	contracts := make(map[string]*big.Int)
//	for i := 0; i < len(arts); i++ {
//		contracts[arts[i].ContractAddress] = big.NewInt(0)
//	}
//	// 获取最近区块高度
//	latest, err := clt.BlockNumber(ctx)
//	if err != nil {
//		return
//	}
//	// 遍历区块
//	for i := 0; i < int(latest); i++ {
//		fmt.Printf("测试 区块高度 %d \n", i)
//		block, err := clt.BlockByNumber(ctx, big.NewInt(int64(i)))
//		if err != nil {
//			return
//		}
//		// 遍历区块交易
//		txs := block.Transactions()
//		if txs.Len() > 0 {
//			for j := 0; j < txs.Len(); j++ {
//				// 创建合约的交易 to字段为合约地址
//				if _, ok := contracts[txs[j].To().String()]; ok {
//					fmt.Printf("测试 匹配交易 %d \n", i)
//					contracts[txs[j].To().String()] = block.Number()
//				}
//			}
//		}
//	}
//
//	for addr, blockNumber := range contracts {
//		var art model.Art
//		rst := db.Where("contract_address = ?", addr).First(&art)
//		if rst.RowsAffected > 0 {
//			rst := db.Model(&art).Updates(model.ChainExchange{BlockNumber: blockNumber.String()})
//			if rst.Error != nil {
//				logger.Sugar().Panicw("try updates db failure", "error", err.Error())
//			}
//		}
//	}
//
//	return
//}
